#pragma once

#include <queue>
#include <set>

//#include "PQueue.h"

using namespace std;

template <class T>
class BaseConCompare
{
public:
	bool operator() (priority_queue<T>& lhs, priority_queue<T>& rhs)
    {
		return (lhs.top() < rhs.top());
	}
	bool equals (priority_queue<T>* lhs, priority_queue<T>* rhs)
    {
		return (lhs.top() == rhs.top());
	}
};

// linCompare is to compare linear T's conCompare is to compare concurent pqueue<T>'s
// Class to prioritize lists of linear objects that can be accessed concurrently
template <class T, class linCompare, class conCompare>
class ConcurrencyQueue
{
	vector<priority_queue<T,vector<T>,linCompare>*> levels;
public:
	inline int size() { return levels.size(); }

	ConcurrencyQueue(int count)
	{
		for(int i = 0; i < count; i++) {
			levels.insert(levels.end(), new priority_queue<T,vector<T>,linCompare>());
		}
	}

	~ConcurrencyQueue()
	{
		int count = levels.size();
		for(int i = 0; i < count; i++) {
			priority_queue<T,vector<T>,linCompare> *top = *levels.end();
			levels.erase(levels.end());
			delete top;
		}
	}

	void push(int level, T item)
	{
		priority_queue<T,vector<T>,linCompare> *queue = levels[level];
		queue->push(item);
	}

	void pop(int level)
	{
		priority_queue<T,vector<T>,linCompare> *queue = levels[level];
		queue->pop();
//		levels.insert(
	}

	T top(int level)
	{
		priority_queue<T,vector<T>,linCompare> *queue = levels[level];
		return queue->top();
	}

	void push(priority_queue<T,vector<T>,linCompare>& queue)
	{
		levels.insert(levels.end(), queue);
	}

	priority_queue<T, vector<T>, conCompare> top()
	{
		priority_queue<T, vector<T>, conCompare> ret;

		for(int i = 0; i < levels.size(); i++) {
			priority_queue<T,vector<T>,linCompare> *queue = levels[i];
			if(!queue->empty())
				ret.push(queue->top());
		}
		return ret;
	}

	bool empty()
	{
		return top().empty();
	}

	bool empty(int level)
	{
		priority_queue<T,vector<T>,linCompare> *queue = levels[level];

		return queue->empty();
	}
};
